package com.google.code.lf.gfm.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import com.google.code.lf.commons.aspect.Loggable;
import com.google.code.lf.commons.exception.NullArgumentException;
import com.google.code.lf.commons.rules.service.AbstractRuleService;
import com.google.code.lf.gfm.model.grisbi.GrisbiFile;
import com.google.code.lf.gfm.model.grisbi.categorie.Categorie;
import com.google.code.lf.gfm.model.grisbi.categorie.SousCategorie;
import com.google.code.lf.gfm.model.grisbi.compte.Compte;
import com.google.code.lf.gfm.model.grisbi.compte.Operation;
import com.google.code.lf.gfm.model.grisbi.tiers.Tiers;
import com.google.code.lf.gfm.model.rules.GrisbiAfterFileImportInput;
import com.google.code.lf.gfm.model.rules.GrisbiAfterFileImportParamFile;
import com.google.code.lf.gfm.service.GrisbiRuleGlobals;
import com.google.code.lf.gfm.service.IGrisbiRuleService;

/**
 * Implémentation du service de règles associées à la manipulation des fichiers de données <a href="http://grisbi.org">Grisbi</a>.
 * <br/>Le moteur de règles utilisé est l'api <a href="http://www.jboss.org/drools/">drools</a>.
 *
 * @author gael.lorent-fonfrede
 */
@Loggable
@Service(IGrisbiRuleService.BEAN_ID)
public class GrisbiRuleService extends AbstractRuleService<GrisbiFile> implements IGrisbiRuleService {
	/**	Nom du bean Spring de la ruleSource associée. */
	private static final String RULE_NAME = "grisbiRuleSource";

	/* (non-Javadoc)
	 * @see com.google.code.lf.gfm.service.IGrisbiRuleService#afterImportProcess(com.google.code.lf.gfm.model.grisbi.GrisbiFile, com.google.code.lf.gfm.model.rules.GrisbiAfterFileImportParam)
	 */
	public GrisbiFile afterImportProcess(final GrisbiFile gsbFile, final GrisbiAfterFileImportParamFile inputParamFile) {
		// Validation des paramètres
		if (gsbFile == null) throw new NullArgumentException("gsbFile");
		if (inputParamFile == null) throw new NullArgumentException("inputParamFile");

		// Gestion des variables globale
		final Map<String, Object> globals = new HashMap<String, Object>();
		globals.put(GrisbiRuleGlobals.LOGGER.getGlobalVariableName(), Logger.getLogger(GrisbiRuleService.class));

		// Préparation des objets à considérer pour le raisonnement :
		final List<Object> ruleInputObjects = new ArrayList<Object>();
		// - Liste des entrées à traiter incluses dans le fichier de paramétrage
		for (final GrisbiAfterFileImportInput grisbiAfterFileImportInput : inputParamFile.getGrisbiAfterFileImportInputs()) {
			ruleInputObjects.add(grisbiAfterFileImportInput);
		}
		// - Fichier Grisbi
		ruleInputObjects.add(gsbFile);
		// - Tiers
		final List<Tiers> tiersListe = gsbFile.getTiers().getTiersListe();
		if (!tiersListe.isEmpty()) {
			for (final Tiers tiers : tiersListe) {
				ruleInputObjects.add(tiers);
			}
		}
		// - Opérations
		final List<Compte> comptes = gsbFile.getComptes().getComptes();
		if (!comptes.isEmpty()) {
			for (final Compte compte : comptes) {
				final List<Operation> operations = compte.getOperations();
				if (!operations.isEmpty()) {
					for (final Operation operation : operations) {
						ruleInputObjects.add(operation);
					}
				}
			}
		}
		// - Catégories et sous-catégories
		final List<Categorie> categories = gsbFile.getCategories().getCategories();
		if (!categories.isEmpty()) {
			for (final Categorie categorie : categories) {
				ruleInputObjects.add(categorie);
				final List<SousCategorie> sousCategories = categorie.getSousCategories();
				if (!sousCategories.isEmpty()) {
					for (final SousCategorie sousCategorie : sousCategories) {
						ruleInputObjects.add(sousCategorie);
					}
				}
			}
		}

		// Exécution des règles
		executeRules(RULE_NAME, ruleInputObjects, globals);

		// Retourne l'objet
		//(Rmq: la référence injectée au départ est utilisée directement, sans utiliser la map retournée par les règles, cela pourrait être à modifier)
		return gsbFile;
	}
}
